package com.iwuyc.tools.commons.codec.type;

import com.iwuyc.tools.commons.codec.Codec;
import com.iwuyc.tools.commons.codec.TypeEnum;
import com.iwuyc.tools.commons.exception.IllegalFormatException;
import com.iwuyc.tools.commons.util.collection.ArrayUtil;
import com.iwuyc.tools.commons.util.math.NumberUtils;

import java.util.Arrays;

public class StringCodec implements Codec<String> {
    private static final byte[] EMPTY_STRING = new byte[]{TypeEnum.STRING.getFlags(), 0, 0, 0, 0};
    private static final byte[] NULL_STRING = new byte[]{TypeEnum.STRING.getFlags(), -1, -1, -1, -1};

    @Override
    public String decode(byte[] data) {
        final int dataLength = ArrayUtil.arrayLength(data);
        if (dataLength < 5) {
            throw new IllegalFormatException("数据长度小于5，字符串类型至少包含5个。");
        }
        final byte typeFlag = data[0];
        if (typeFlag != TypeEnum.STRING.getFlags()) {
            throw new IllegalArgumentException("The data is not a string type");
        }

        final byte[] contentLengthBytes = Arrays.copyOfRange(data, 1, 5);
        final int contentLength = NumberUtils.toInt(contentLengthBytes);
        if (contentLength < 0) {
            return null;
        }
        if (contentLength > dataLength - 5) {
            throw new IllegalFormatException("长度位中显示存在" + contentLength + "字节，但是实际数据长度仅有" + dataLength + "字节");
        }
        if (contentLength == 0) {
            return "";
        }
        final byte[] contentBytes = Arrays.copyOfRange(data, 5, contentLength + 5);
        return new String(contentBytes);
    }

    @Override
    public byte[] encode(String data) {
        if (data == null) {
            return Arrays.copyOf(NULL_STRING, NULL_STRING.length);
        }
        if (data.isEmpty()) {
            return Arrays.copyOf(EMPTY_STRING, EMPTY_STRING.length);
        }
        final byte[] dataBytes = data.getBytes();
        // 第一位为类型，第二位到第五位为长度，后面的为实际数据
        final int dataLength = dataBytes.length;
        final byte[] result = new byte[1 + 4 + dataLength];
        result[0] = TypeEnum.STRING.getFlags();
        final byte[] dataLengthBytes = NumberUtils.toBytes(dataLength);

        int currors = 1;
        System.arraycopy(dataLengthBytes, 0, result, currors, dataLengthBytes.length);

        currors += dataLengthBytes.length;
        System.arraycopy(dataBytes, 0, result, currors, dataBytes.length);
        return result;
    }

    @Override
    public TypeEnum[] supportedTypes() {
        return new TypeEnum[]{TypeEnum.STRING};
    }
}
